#include "cst92f2x.h"
#include "gpio.h"
#include "pwrmgr.h"
#include "log.h"
#include "i2c_master.h"
#include "clock.h"
#include "jump_function.h"


#define I2C_BYTE_TIMEOUT  100   //100ms for an Byte operation

#define I2C_OP_STATE_MASTER_WR	0
#define I2C_OP_STATE_MASTER_RD	1
#define I2C_OP_STATE_SLAVE_WR	2
#define I2C_OP_STATE_SLAVE_RD	3

/**
* @struct I2cBufCtl_t
* @brief i2c buffer information
*/
typedef struct {
	uint16_t  bufOffset;
	uint16_t  bufSize;
	uint8_t*  buf;
}I2cBufCtl_t;

/**
* @struct I2cCtl_t
* @brief i2c control information
*/
typedef struct {
	bool    	enable;
	I2cCfg_t	cfg;
	uint8_t   busy;
	uint8_t 	opState;	//I2C_OP_STATE_MASTER_WR, I2C_OP_STATE_MASTER_RD, I2C_OP_STATE_SLAVE_WR, I2C_OP_STATE_SLAVE_RD
	uint16_t readCmdCnt;
	uint32_t devReg;
	uint8_t devRegLen;
	I2cBufCtl_t i2cBufCtl;
}I2cCtl_t;

I2cCtl_t i2cCtl[2];


/**
* @fn static void HalI2cErrorIRQHandler(AP_I2C_TypeDef *I2Cx, uint32_t irq)
* @brief i2c error interrupt process
* @param I2Cx: i2c peripheral number: I2C0 or I2C1.
* @param irq: interrupt status
* @return NONE.
*/
static void HalI2cErrorIRQHandler(AP_I2C_TypeDef *I2Cx, uint32_t irq)
{
	uint8_t index;
	I2cEvt_t evt;
	uint32_t temp;
	index = (I2Cx == AP_I2C0) ? 0 : 1;
	temp = I2Cx->IC_TX_ABRT_SOURCE;
	LOG("Error:%x,%x\r\n",irq,temp);
	I2Cx->IC_CLR_INTR;
	I2Cx->IC_ENABLE = 0;
	while(I2Cx->IC_ENABLE_STATUS & 0x01);	//when I2C disable, should check it until it is disabled
	I2Cx->IC_ENABLE = 1;
	i2cCtl[index].busy = FALSE;
	if(i2cCtl[index].cfg.evtHdlCB) {
		evt.type = I2C_EVT_TYPE_ERROR;
		evt.len = 4;
		evt.data[0] = BREAK_UINT32(temp, 0);
		evt.data[1] = BREAK_UINT32(temp, 1);
		evt.data[2] = BREAK_UINT32(temp, 2);
		evt.data[3] = BREAK_UINT32(temp, 3);
		i2cCtl[index].cfg.evtHdlCB(&evt);
	}
}

/**
* @fn static void HalI2cReadReqIRQHandler(AP_I2C_TypeDef *I2Cx)
* @brief i2c read request interrupt process
* @param I2Cx: i2c peripheral number: I2C0 or I2C1.
* @return NONE.
*/
static void HalI2cReadReqIRQHandler(AP_I2C_TypeDef *I2Cx)
{
	uint8_t index;
	I2cEvt_t evt;
	index = (I2Cx == AP_I2C0) ? 0 : 1;
	if(i2cCtl[index].cfg.evtHdlCB) {
		evt.type = I2C_EVT_TYPE_RD_REQ;
		evt.len = 0;
		i2cCtl[index].cfg.evtHdlCB(&evt);
	}
	I2Cx->IC_CLR_RD_REG;
}

/**
* @fn static void HalI2cTxIRQHandler(AP_I2C_TypeDef *I2Cx)
* @brief i2c transmit interrupt process
* @param I2Cx: i2c peripheral number: I2C0 or I2C1.
* @return NONE.
*/
static void HalI2cTxIRQHandler(AP_I2C_TypeDef *I2Cx)
{
	uint8_t index;
	uint16_t i, len, maxLen;
	index = (I2Cx == AP_I2C0) ? 0 : 1;
	HAL_ENTER_CRITICAL_SECTION();
	len = i2cCtl[index].i2cBufCtl.bufSize - i2cCtl[index].i2cBufCtl.bufOffset;
	maxLen = I2C_FIFO_SIZE-1 - I2Cx->IC_TXFLR;
	if(len > maxLen) {
		len = maxLen;
	}
	for(i=0;i<len;i++) {
		I2Cx->IC_DATA_CMD = i2cCtl[index].i2cBufCtl.buf[i2cCtl[index].i2cBufCtl.bufOffset++];
	}
	if(i2cCtl[index].i2cBufCtl.bufOffset >= i2cCtl[index].i2cBufCtl.bufSize) {
		I2Cx->IC_INTR_MASK &= ~I2C_MASK_TX_EMPTY;
	}
	HAL_EXIT_CRITICAL_SECTION();
}

/**
* @fn static void HalI2cRxIRQHandler(AP_I2C_TypeDef *I2Cx)
* @brief i2c receive interrupt process
* @param I2Cx: i2c peripheral number: I2C0 or I2C1.
* @return NONE.
*/
static void HalI2cRxIRQHandler(AP_I2C_TypeDef *I2Cx)
{
	uint16_t i, len, maxLen, offset;
	uint8_t index;
	
	index = (I2Cx == AP_I2C0) ? 0 : 1;
	HAL_ENTER_CRITICAL_SECTION();
	//receive data
	len = I2Cx->IC_RXFLR;
	offset = i2cCtl[index].i2cBufCtl.bufOffset;
	for(i=0;i<len;i++) {
		i2cCtl[index].i2cBufCtl.buf[offset++] = (I2Cx->IC_DATA_CMD&0xFF);
	}
	i2cCtl[index].i2cBufCtl.bufOffset = offset;
	//send read cmd
	len = I2C_FIFO_SIZE-1 - I2Cx->IC_RXFLR;
	maxLen = I2C_FIFO_SIZE-1 - I2Cx->IC_TXFLR;
	if(maxLen > len) {
		maxLen = len;
	}
	len = i2cCtl[index].i2cBufCtl.bufSize - i2cCtl[index].readCmdCnt;
	if(len > maxLen) {
		len = maxLen;
	}
	for(i=0;i<len;i++) {
		I2Cx->IC_DATA_CMD = 0x100;   //Read
	}
	i2cCtl[index].readCmdCnt += len;
	
	HAL_EXIT_CRITICAL_SECTION();
	if(i2cCtl[index].i2cBufCtl.bufOffset >= i2cCtl[index].i2cBufCtl.bufSize) {
		I2Cx->IC_INTR_MASK &= ~I2C_MASK_RX_FULL;
	}
}

/**
* @fn static void HalI2cStopDetIRQHandler(AP_I2C_TypeDef *I2Cx)
* @brief i2c stop condition occurred interrupt process
* @param I2Cx: i2c peripheral number: I2C0 or I2C1.
* @return NONE.
*/
static void HalI2cStopDetIRQHandler(AP_I2C_TypeDef *I2Cx)
{
	uint8_t index;
	I2cEvt_t evt;
	uint8_t i,len;
	uint8_t flag = 0;
	index = (I2Cx == AP_I2C0) ? 0 : 1;
	if(i2cCtl[index].cfg.i2cWorkMode == I2C_WORK_MODE_INT) {
		if(i2cCtl[index].opState == I2C_OP_STATE_MASTER_RD) {
			//read data
			len = I2Cx->IC_RXFLR;
			for(i=0;i<len;i++) {
				i2cCtl[index].i2cBufCtl.buf[i2cCtl[index].i2cBufCtl.bufOffset++] = (I2Cx->IC_DATA_CMD&0xFF);
			}
			if(i2cCtl[index].i2cBufCtl.bufOffset >= i2cCtl[index].i2cBufCtl.bufSize) {	//finish
				hal_pwrmgr_unlock((per_module_t)(MOD_I2C0+index));
				HAL_ENTER_CRITICAL_SECTION();
				NVIC_DisableIRQ((IRQn_Type)(I2C0_IRQn + index));
				HAL_EXIT_CRITICAL_SECTION();
				I2Cx->IC_INTR_MASK = 0;
				i2cCtl[index].busy = FALSE;
				flag = 1;
			}
			else {	//when interrupt is not responsed quickly, I2C stop condition will be send, we should continue to transfer
				I2Cx->IC_ENABLE=0;
				while(I2Cx->IC_ENABLE_STATUS & 0x01);	//when I2C disable, should check it until it is disabled
				I2Cx->IC_ENABLE=1;
				//send reg address
				for (i=i2cCtl[index].devRegLen; i>0; i--) {
					I2Cx->IC_DATA_CMD = (((i2cCtl[index].devReg+i2cCtl[index].i2cBufCtl.bufOffset) >> (8 * (i-1))) & 0xFF);
				}
				i2cCtl[index].readCmdCnt = i2cCtl[index].i2cBufCtl.bufOffset;
				HalI2cRxIRQHandler(I2Cx);
			}
		}
		else if(i2cCtl[index].opState == I2C_OP_STATE_MASTER_WR){
			if(i2cCtl[index].i2cBufCtl.bufOffset >= i2cCtl[index].i2cBufCtl.bufSize) //finish
			{
				hal_pwrmgr_unlock((per_module_t)(MOD_I2C0+index));
				HAL_ENTER_CRITICAL_SECTION();
				NVIC_DisableIRQ((IRQn_Type)(I2C0_IRQn + index));
				HAL_EXIT_CRITICAL_SECTION();
				I2Cx->IC_INTR_MASK = 0;
				i2cCtl[index].busy = FALSE;
				flag = 1;
			}
			else {	//when interrupt is not responsed quickly, I2C stop condition will be send, we should continue to transfer
				I2Cx->IC_ENABLE=0;
				while(I2Cx->IC_ENABLE_STATUS & 0x01);	//when I2C disable, should check it until it is disabled
				I2Cx->IC_ENABLE=1;
				//send reg address
				for (i=i2cCtl[index].devRegLen; i>0; i--) {
					I2Cx->IC_DATA_CMD = (((i2cCtl[index].devReg+i2cCtl[index].i2cBufCtl.bufOffset) >> (8 * (i-1))) & 0xFF);
				}
				HalI2cTxIRQHandler(I2Cx);
			}
		}
	}
	if(i2cCtl[index].cfg.evtHdlCB && (flag == 1)) {
		evt.type = I2C_EVT_TYPE_TRANSFER_COMPLETED;
		evt.len = 0;
		i2cCtl[index].cfg.evtHdlCB(&evt);
	}
	I2Cx->IC_CLR_STOP_DET;
}

/**
* @fn static void __attribute__((used)) HalI2c0IRQHandler(void)
* @brief i2c0 interrupt function
* @param NONE.
* @return NONE.
*/
static void __attribute__((used)) HalI2c0IRQHandler(void)
{
	uint32_t irq = AP_I2C0->IC_INTR_STAT;
	if((irq & I2C_MASK_RD_REQ) == I2C_MASK_RD_REQ) {
		HalI2cReadReqIRQHandler(AP_I2C0);
	}
	else if((irq & I2C_MASK_RX_FULL) == I2C_MASK_RX_FULL) {
		HalI2cRxIRQHandler(AP_I2C0);
	}
	else if((irq & I2C_MASK_TX_EMPTY) == I2C_MASK_TX_EMPTY) {
		HalI2cTxIRQHandler(AP_I2C0);
	}
	else if((irq & I2C_MASK_STOP_DET) == I2C_MASK_STOP_DET) {
		HalI2cStopDetIRQHandler(AP_I2C0);
	}
	else if(irq){	// error occured
		HalI2cErrorIRQHandler(AP_I2C0, irq);
	}
}

/**
* @fn static void __attribute__((used)) HalI2c1IRQHandler(void)
* @brief i2c1 interrupt function
* @param NONE.
* @return NONE.
*/
static void __attribute__((used)) HalI2c1IRQHandler(void)
{
	uint32_t irq = AP_I2C1->IC_INTR_STAT;
	if((irq & I2C_MASK_RD_REQ) == I2C_MASK_RD_REQ) {
		HalI2cReadReqIRQHandler(AP_I2C1);
	}
	else if((irq & I2C_MASK_RX_FULL) == I2C_MASK_RX_FULL) {
		HalI2cRxIRQHandler(AP_I2C1);
	}
	else if((irq & I2C_MASK_TX_EMPTY) == I2C_MASK_TX_EMPTY) {
		HalI2cTxIRQHandler(AP_I2C1);
	}
	else if((irq & I2C_MASK_STOP_DET) == I2C_MASK_STOP_DET) {
		HalI2cStopDetIRQHandler(AP_I2C1);
	}
	else if(irq){	// error occured
		HalI2cErrorIRQHandler(AP_I2C1, irq);
	}
}

/**
* @fn static void HalI2cHwInit(AP_I2C_TypeDef* I2Cx)
* @brief Initialize I2C hardware, It consists of GPIO initialization and I2C peripheral initialization
* @param I2Cx: i2c peripheral number: I2C0 or I2C1.
* @return NONE.
*/
static void HalI2cHwInit(AP_I2C_TypeDef* I2Cx)
{
	uint8_t index;
	I2cCfg_t *pcfg;
	uint32_t pclk = clk_get_pclk();
	index = (I2Cx == AP_I2C0) ? 0 : 1;
	pcfg = &(i2cCtl[index].cfg);
	
	if(index == 0){
        hal_clk_gate_enable(MOD_I2C0);
    }
    else if(index == 1){
        hal_clk_gate_enable(MOD_I2C1);
    }	//enable I2C clock
	//init GPIO

  	HalGpioPupdConfig(pcfg->i2cScl , STRONG_PULL_UP);
  	HalGpioPupdConfig(pcfg->i2cSda , STRONG_PULL_UP);
	if (index == 0) {
		HalGpioFmuxConfig(pcfg->i2cScl, FMUX_IIC0_SCL);
		HalGpioFmuxConfig(pcfg->i2cSda, FMUX_IIC0_SDA);
	}
	else {
		HalGpioFmuxConfig(pcfg->i2cScl, FMUX_IIC1_SCL);
		HalGpioFmuxConfig(pcfg->i2cSda, FMUX_IIC1_SDA);
	}
	//init I2C peripheral
	I2Cx->IC_ENABLE=0;
	while(I2Cx->IC_ENABLE_STATUS & 0x01);	//when I2C disable, should check it until it is disabled
	if(pcfg->i2cRole == I2C_ROLE_MASTER) {
		I2Cx->IC_CON=0x61;
		if(pcfg->i2cAddressBit == I2C_ADDRESS_BIT_10) {
			I2Cx->IC_CON = (I2Cx->IC_CON | 0x10);
		}
		if(pcfg->i2cClock == I2C_CLOCK_100K) {
			I2Cx->IC_CON= ((I2Cx->IC_CON) & 0xfffffff9)|(0x01 << 1);
			if(pclk==16000000){
				I2Cx->IC_SS_SCL_HCNT=70;  //16
				I2Cx->IC_SS_SCL_LCNT=76;  //32)
			}else if(pclk==32000000){
				I2Cx->IC_SS_SCL_HCNT=148;  //16
				I2Cx->IC_SS_SCL_LCNT=154;  //32)
			}else if(pclk==48000000){
				I2Cx->IC_SS_SCL_HCNT=230;  //16
				I2Cx->IC_SS_SCL_LCNT=236;  //32)
			}else if(pclk==64000000){
				I2Cx->IC_SS_SCL_HCNT=307;  //16
				I2Cx->IC_SS_SCL_LCNT=320;  //32)
			}else if(pclk==96000000){
				I2Cx->IC_SS_SCL_HCNT=460;  //16
				I2Cx->IC_SS_SCL_LCNT=470;  //32)
			}
		}else if(pcfg->i2cClock == I2C_CLOCK_400K){
			I2Cx->IC_CON= ((I2Cx->IC_CON) & 0xfffffff9)|(0x02 << 1);
			if(pclk==16000000){
				I2Cx->IC_FS_SCL_HCNT=10;  //16
				I2Cx->IC_FS_SCL_LCNT=17;  //32)
			}else if(pclk==32000000){
				I2Cx->IC_FS_SCL_HCNT=30;  //16
				I2Cx->IC_FS_SCL_LCNT=35;  //32)
			}else if(pclk==48000000){
				I2Cx->IC_FS_SCL_HCNT=48;  //16
				I2Cx->IC_FS_SCL_LCNT=54;  //32)
			}else if(pclk==64000000){
				I2Cx->IC_FS_SCL_HCNT=67;  //16
				I2Cx->IC_FS_SCL_LCNT=75;  //32)
			}else if(pclk==96000000){
				I2Cx->IC_FS_SCL_HCNT=105;  //16
				I2Cx->IC_FS_SCL_LCNT=113;  //32)
			}
		}
//		I2Cx->IC_TAR = (pcfg->i2cAddress>>1);
		I2Cx->IC_TAR = I2C_MASTER_ADDR_DEF;
		I2Cx->IC_INTR_MASK=0;
		I2Cx->IC_RX_TL=0x0;
		I2Cx->IC_TX_TL=0x0;	    
	}
	else if(pcfg->i2cRole == I2C_ROLE_SLAVE) {
		I2Cx->IC_SAR=(pcfg->i2cAddress>>1);
		I2Cx->IC_CON=0x24;
		I2Cx->IC_INTR_MASK=0x20; //unmask required interrupts
	}
	I2Cx->IC_ENABLE = 1; //disable

  	NVIC_EnableIRQ((IRQn_Type)(I2C0_IRQn + index));
	NVIC_SetPriority((IRQn_Type)(I2C0_IRQn + index), IRQ_PRIO_HAL);
	//I2Cx->IC_ENABLE=1;
}

/**
* @fn static void HalI2c0WakeupCallback(void)
* @brief I2C0 callback function when wakeup from sleep 
* @param NONE
* @return NONE
*/
static void HalI2c0WakeupCallback(void)
{
	HalI2cHwInit(AP_I2C0);
}

/**
* @fn static void HalI2c1WakeupCallback(void)
* @brief I2C1 callback function when wakeup from sleep 
* @param NONE
* @return NONE
*/
static void HalI2c1WakeupCallback(void)
{
	HalI2cHwInit(AP_I2C1);
}

/**
* @fn static void HalI2cTargetAddrUpdate(AP_I2C_TypeDef *I2Cx, uint16_t addr)
* @brief update target address,(i2c work in master mode)
* @param I2Cx: i2c peripheral number: I2C0 or I2C1.
* @param addr: target address.
* @return NONE.
*/
static void HalI2cTargetAddrUpdate(AP_I2C_TypeDef *I2Cx, uint16_t addr)
{
	I2Cx->IC_ENABLE=0;
	while(I2Cx->IC_ENABLE_STATUS & 0x01);	//when I2C disable, should check it until it is disabled
    I2Cx->IC_TAR = addr;
    I2Cx->IC_ENABLE=1;
}

/**
* @fn static ErrCode_t HalI2cWaitStopCondition(AP_I2C_TypeDef *I2Cx)
* @brief Wait for stop condition occurred
* @param I2Cx: i2c peripheral number: I2C0 or I2C1.
* @return error code.
*/
ErrCode_t HalI2cWaitStopCondition(AP_I2C_TypeDef *I2Cx)
{
	uint32_t t0 = hal_systick();
	while(1){
		if(I2Cx->IC_RAW_INTR_STAT & I2C_MASK_STOP_DET) {	//check STOP condition 
			break;
		}
		if(hal_ms_intv(t0) > I2C_BYTE_TIMEOUT){
			//disable I2C
			I2Cx->IC_ENABLE=0;
			while(I2Cx->IC_ENABLE_STATUS & 0x01);	//when I2C disable, should check it until it is disabled
			I2Cx->IC_ENABLE=1;
			LOG("HalI2cWaitStopCondition Timeout\r\n");
			return ERR_TIMEOUT;
		}
	}
	return ERR_NONE;
}

/**
* @fn ErrCode_t HalI2cInit(AP_I2C_TypeDef *I2Cx, I2cCfg_t *cfg)
* @brief i2c initial function
* @param I2Cx: i2c peripheral number: I2C0 or I2C1.
* @param cfg: i2c config.
* @return error code.
*/
ErrCode_t HalI2cInit(AP_I2C_TypeDef *I2Cx, I2cCfg_t *cfg)
{
	uint8_t index;
	if(I2Cx == NULL)
	{
		return ERR_NULL;
	}
	if(cfg->i2cScl >=GPIO_NUM ||cfg->i2cSda  >=GPIO_NUM || cfg->i2cScl == cfg->i2cSda)
	{
		return ERR_NOT_SUPPORTED;
	}
	if(cfg->i2cClock >I2C_CLOCK_400K || cfg->i2cAddressBit >I2C_ADDRESS_BIT_7)
	{
		return ERR_INVALID_PARAM;
	}
	if(cfg->i2cWorkMode >I2C_WORK_MODE_INT)
	{
		return ERR_INVALID_PARAM;
	}
	index = (I2Cx == AP_I2C0) ? 0 : 1;
	if(i2cCtl[index].enable) {
		return ERR_BUSY;
	}
	osal_memset(&i2cCtl[index], 0, sizeof(I2cCtl_t));
	osal_memcpy(&i2cCtl[index].cfg, cfg, sizeof(I2cCfg_t));
	i2cCtl[index].enable = TRUE;
	if(index == 0) {
		hal_pwrmgr_register(MOD_I2C0, NULL, HalI2c0WakeupCallback);
		JUMP_FUNCTION(V12_IRQ_HANDLER)                  =   (uint32_t)&HalI2c0IRQHandler;
	}
	else {
		hal_pwrmgr_register(MOD_I2C1, NULL, HalI2c1WakeupCallback);
		JUMP_FUNCTION(V13_IRQ_HANDLER)                  =   (uint32_t)&HalI2c1IRQHandler;
	}
	HalI2cHwInit(I2Cx);
	return ERR_NONE;
}

/**
* @fn ErrCode_t HalI2cMasterWrite(AP_I2C_TypeDef *I2Cx, uint16_t devAddr, uint32_t reg,uint8_t regLen, uint8_t *txBuf, uint16_t txBufLen)
* @brief i2c master write function
* @param I2Cx: i2c peripheral number: I2C0 or I2C1.
* @param devAddr: slave device address.
* @param reg: slave device register address
* @param regLen: length of slave device register address 
* @param txBuf: transmit data buffer
* @param txBufLen: transmit data length
* @return error code.
*/
ErrCode_t HalI2cMasterWrite(AP_I2C_TypeDef *I2Cx, uint16_t devAddr, uint32_t reg,uint8_t regLen, uint8_t *txBuf, uint16_t txBufLen)
{
	uint8_t index;
	uint32_t i, txLen;
	ErrCode_t ret = ERR_NONE;
	if(I2Cx == NULL)
	{
		return ERR_NULL;
	}
	index = (I2Cx == AP_I2C0) ? 0 : 1;
	if(regLen > 4) {
		return ERR_INVALID_PARAM;
	}
	if(txBuf  == NULL || txBufLen == 0)
	{
		return ERR_INVALID_DATA;
	}
	HalI2cTargetAddrUpdate(I2Cx, devAddr>>1);
	i2cCtl[index].opState = I2C_OP_STATE_MASTER_WR;
	i2cCtl[index].devReg = reg;
	i2cCtl[index].devRegLen = regLen;
	if(i2cCtl[index].cfg.i2cWorkMode == I2C_WORK_MODE_POLLING) {
		i2cCtl[index].busy = TRUE;
		//send reg address
		for (i=regLen; i>0; i--) {
			I2Cx->IC_DATA_CMD = ((reg >> (8 * (i-1))) & 0xFF);
		}
		//send data
		i=0;
		while(i<txBufLen) {
			if(I2C_TX_FIFO_NOT_FULL()) {
				I2Cx->IC_DATA_CMD = txBuf[i++];
			}
			//maybe dead loop
		}
		ret = HalI2cWaitStopCondition(I2Cx);
		i2cCtl[index].busy = FALSE;
	}
	else if(i2cCtl[index].cfg.i2cWorkMode == I2C_WORK_MODE_INT){
		if(i2cCtl[index].busy) {
			return ERR_BUSY;
		}
		i2cCtl[index].busy = TRUE;
		I2Cx->IC_TX_TL=0x3;
		
		i2cCtl[index].i2cBufCtl.buf = txBuf;
		i2cCtl[index].i2cBufCtl.bufOffset = 0;
		i2cCtl[index].i2cBufCtl.bufSize = txBufLen;
		
		hal_pwrmgr_lock((per_module_t)(MOD_I2C0 + index));
		if(regLen + txBufLen > I2C_FIFO_SIZE) {
			txLen = I2C_FIFO_SIZE-regLen;
		}
		else {
			txLen = txBufLen;
		}
		HAL_ENTER_CRITICAL_SECTION();
		//send reg address
		for (i=regLen; i>0; i--) {
			I2Cx->IC_DATA_CMD = ((reg >> (8 * (i-1))) & 0xFF);
		}
		//send data
		i=0;
		while(i<txLen) {
			if(I2C_TX_FIFO_NOT_FULL()) {
				I2Cx->IC_DATA_CMD = txBuf[i++];
			}
		}
		i2cCtl[index].i2cBufCtl.bufOffset = txLen;
		HAL_EXIT_CRITICAL_SECTION();
		//enable interrupt
		I2Cx->IC_INTR_MASK = (I2C_MASK_TX_EMPTY | I2C_MASK_STOP_DET | I2C_MASK_TX_OVER | I2C_MASK_RX_UNDER | I2C_MASK_RX_OVER | I2C_MASK_TX_ABRT);
		HAL_ENTER_CRITICAL_SECTION();
		NVIC_EnableIRQ((IRQn_Type)(I2C0_IRQn + index));
		HAL_EXIT_CRITICAL_SECTION();
	}
	return ret;
}

/**
* @fn ErrCode_t HalI2cMasterRead(AP_I2C_TypeDef *I2Cx, uint16_t devAddr, uint32_t reg,uint8_t regLen, uint8_t *rxBuf, uint16_t rxBufLen)
* @brief i2c master read function
* @param I2Cx: i2c peripheral number: I2C0 or I2C1.
* @param devAddr: slave device address.
* @param reg: slave device register address
* @param regLen: length of slave device register address 
* @param rxBuf: receive data buffer
* @param rxBufLen: receive data length
* @return error code.
*/
ErrCode_t HalI2cMasterRead(AP_I2C_TypeDef *I2Cx, uint16_t devAddr, uint32_t reg,uint8_t regLen, uint8_t *rxBuf, uint16_t rxBufLen)
{
	uint8_t index;
	uint32_t i, rxLen, maxLen, len;
	ErrCode_t ret = ERR_NONE;
	uint32_t t0;
	if(I2Cx == NULL)
	{
		return ERR_NULL;
	}
	index = (I2Cx == AP_I2C0) ? 0 : 1;
	if(regLen > 4) {
		return ERR_INVALID_PARAM;
	}
	if(rxBuf  == NULL || rxBufLen == 0)
	{
		return ERR_INVALID_DATA;
	}
	HalI2cTargetAddrUpdate(I2Cx, devAddr>>1);
	i2cCtl[index].opState = I2C_OP_STATE_MASTER_RD;
	i2cCtl[index].devReg = reg;
	i2cCtl[index].devRegLen = regLen;
	if(i2cCtl[index].cfg.i2cWorkMode == I2C_WORK_MODE_POLLING) {
		i2cCtl[index].busy = TRUE;
		//send reg address
		for (i=regLen; i>0; i--) {
			I2Cx->IC_DATA_CMD = ((reg >> (8 * (i-1))) & 0xFF);
		}
		//receive data
		t0 = hal_systick();
		rxLen=0;
		i2cCtl[index].readCmdCnt = 0;
		while(rxLen<rxBufLen) {
			maxLen = I2C_FIFO_SIZE - I2Cx->IC_TXFLR;
			len = rxBufLen - i2cCtl[index].readCmdCnt;
			if(len > maxLen) {
				len = maxLen;
			}
			HAL_ENTER_CRITICAL_SECTION();
			//send read cmd
			for(i=0;i<len;i++) {
				I2Cx->IC_DATA_CMD = 0x100;   //Read
			}
			i2cCtl[index].readCmdCnt += len;
			while(I2C_RX_FIFO_NOT_EMPTY()){
				rxBuf[rxLen++] = (I2Cx->IC_DATA_CMD&0xff);
			}
			HAL_EXIT_CRITICAL_SECTION();
			if(hal_ms_intv(t0) > I2C_BYTE_TIMEOUT*rxBufLen){
				//disable I2C
				I2Cx->IC_ENABLE=0;
				while(I2Cx->IC_ENABLE_STATUS & 0x01);	//when I2C disable, should check it until it is disabled
				I2Cx->IC_ENABLE=1;
				LOG("I2C Read Timeout\r\n");
				return ERR_TIMEOUT;
			}
		}
		ret = HalI2cWaitStopCondition(I2Cx);
		i2cCtl[index].busy = FALSE;
	}
	else if(i2cCtl[index].cfg.i2cWorkMode == I2C_WORK_MODE_INT){
		if(i2cCtl[index].busy) {
			return ERR_BUSY;
		}
		i2cCtl[index].busy = TRUE;
		/*if(rxBufLen > 0x1) {
			I2Cx->IC_RX_TL=0x1;
		}
		else {
			I2Cx->IC_RX_TL=rxBufLen;
		}*/
		I2Cx->IC_RX_TL=0x3;
		i2cCtl[index].readCmdCnt = 0;
		i2cCtl[index].i2cBufCtl.buf = rxBuf;
		i2cCtl[index].i2cBufCtl.bufOffset = 0;
		i2cCtl[index].i2cBufCtl.bufSize = rxBufLen;
		
		hal_pwrmgr_lock((per_module_t)(MOD_I2C0 + index));
		HAL_ENTER_CRITICAL_SECTION();
		//send reg address
		for (i=regLen; i>0; i--) {
			I2Cx->IC_DATA_CMD = ((reg >> (8 * (i-1))) & 0xFF);
		}
		//send read cmd
		maxLen = I2C_FIFO_SIZE - I2Cx->IC_TXFLR;
		len = rxBufLen - i2cCtl[index].readCmdCnt;
		if(len > maxLen) {
			len = maxLen;
		}
		for(i=0;i<len;i++) {
			I2Cx->IC_DATA_CMD = 0x100;   //Read
		}
		i2cCtl[index].readCmdCnt += len;
		//enable interrupt
		I2Cx->IC_INTR_MASK = (I2C_MASK_RX_FULL | I2C_MASK_STOP_DET  | I2C_MASK_TX_OVER | I2C_MASK_RX_UNDER | I2C_MASK_RX_OVER | I2C_MASK_TX_ABRT);
		NVIC_EnableIRQ((IRQn_Type)(I2C0_IRQn + index));
		HAL_EXIT_CRITICAL_SECTION();
	}
	return ret;
}

/**
* @fn ErrCode_t HalI2cGetTransferComplete(AP_I2C_TypeDef *I2Cx)
* @brief Get transfer complete status
* @param I2Cx: i2c peripheral number: I2C0 or I2C1.
* @return error code.
*/
ErrCode_t HalI2cGetTransferComplete(AP_I2C_TypeDef *I2Cx)
{
	uint8_t index;
	if(I2Cx == NULL)
	{
		return ERR_NULL;
	}
	index = (I2Cx == AP_I2C0) ? 0 : 1;
	if(i2cCtl[index].busy) {
		return ERR_BUSY;
	}
	return ERR_NONE;
}

